//
// Copyright (C) 2011 Steve Channell steve.channell@cepheis.com
//
// This file is part of Cephei.QL, an open-source library wrapper 
// arround QuantLib http://quantlib.org/
//
// Cephei.QL is open source software: you can redistribute it and/or modify it
// under the terms of the license.  You should have received a
// copy of the license along with this program; if not, please email
// <support@cepheis.com>. The license is also available online at
// <http://cepheis.com/license.htm>.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE.  See the license for more details.
//
// Version 2.101
//#include "stdafx.h"
#include "BMAIndex.h"
using namespace Cephei::QL::Indexes;
#include <gen/QL/Termstructures/YieldTermStructure.h>
#include <gen/QL/Times/Schedule.h>
#include <gen/QL/Currency.h>
#include <gen/QL/Times/DayCounter.h>
#include <gen/QL/Times/Calendar.h>
#include <gen/QL/Times/Period.h>
#include <gen/QL/Indexes/InterestRateIndex.h>
using namespace Cephei::QL::Termstructures;
using namespace Cephei::QL::Times;
using namespace Cephei::QL;
#define HANDLE
#undef ABSTRACT
#undef STRUCT
Cephei::QL::Indexes::CBMAIndex::CBMAIndex (Microsoft::FSharp::Core::FSharpOption<Cephei::QL::Termstructures::IYieldTermStructure^>^ h) : CInterestRateIndex(CBMAIndex::typeid)
{
    CYieldTermStructure^ _Ch;
    try
    {
#ifdef HANDLE
        _phBMAIndex = NULL;
#endif
        if (Microsoft::FSharp::Core::FSharpOption<Cephei::QL::Termstructures::IYieldTermStructure^>::IsSome::get (h))
        {
            _Ch = safe_cast<CYieldTermStructure^> (h->Value);
            _Ch->Lock();
        }
        Handle<QuantLib::YieldTermStructure>& _h = 
            (Microsoft::FSharp::Core::FSharpOption<Cephei::QL::Termstructures::IYieldTermStructure^>::IsSome::get (h) ? static_cast<Handle<QuantLib::YieldTermStructure>&> (_Ch->GetHandle ()) : Handle<QuantLib::YieldTermStructure>()); //1
        _ppBMAIndex = new boost::shared_ptr<QuantLib::BMAIndex> (new QuantLib::BMAIndex ( _h ));
        SetInterestRateIndex (boost::dynamic_pointer_cast<QuantLib::InterestRateIndex> (*_ppBMAIndex));
	}
    catch (QuantLib::Error& _error)
    {
        if (_error.what())
		    throw gcnew NativeExcpetion (gcnew System::String(_error.what()));
        else
		    throw gcnew NativeExcpetion (gcnew System::String("Unknown quantlib error"));
        
    }
	catch (std::exception& _error)
	{
        if (_error.what())
		    throw gcnew NativeExcpetion (gcnew System::String(_error.what()));
        else
		    throw gcnew NativeExcpetion (gcnew System::String("Unknown std::exception"));
	}
    finally
    {
        if (_Ch != nullptr) _Ch->Unlock();
    }
}
Cephei::QL::Indexes::CBMAIndex::CBMAIndex (boost::shared_ptr<QuantLib::BMAIndex>& childNative, Object^ owner) : CInterestRateIndex(CBMAIndex::typeid)
{
#ifdef HANDLE
	_phBMAIndex = NULL;
#endif
	_ppBMAIndex = &childNative;
    _ppInterestRateIndex = new boost::shared_ptr<QuantLib::InterestRateIndex> (boost::dynamic_pointer_cast<QuantLib::InterestRateIndex> (*_ppBMAIndex));
}
Cephei::QL::Indexes::CBMAIndex::CBMAIndex (QuantLib::BMAIndex& childNative, Object^ owner) : CInterestRateIndex(CBMAIndex::typeid)
{
#ifdef HANDLE
	_phBMAIndex = NULL;
#endif
	_ppBMAIndex = new boost::shared_ptr<QuantLib::BMAIndex> (&childNative);
    _ppInterestRateIndex = new boost::shared_ptr<QuantLib::InterestRateIndex> (boost::dynamic_pointer_cast<QuantLib::InterestRateIndex> (*_ppBMAIndex));
    _BMAIndexOwner = owner;
    _InterestRateIndexOwner = owner;
}

Cephei::QL::Indexes::CBMAIndex::CBMAIndex (CBMAIndex^ copy) : CInterestRateIndex(CBMAIndex::typeid)
{
#ifdef HANDLE
	_phBMAIndex = NULL;
#endif
	if (copy->HasNative() != NULL)
    {
		_ppBMAIndex = new boost::shared_ptr<QuantLib::BMAIndex> (copy->GetShared());
        _ppInterestRateIndex = new boost::shared_ptr<QuantLib::InterestRateIndex> (boost::dynamic_pointer_cast<QuantLib::InterestRateIndex> (*_ppBMAIndex));
    }
}
Cephei::QL::Indexes::CBMAIndex::CBMAIndex (System::Type^ t) : CInterestRateIndex(CBMAIndex::typeid)
{
#ifdef HANDLE
	_phBMAIndex = NULL;
#endif
	if (!t->IsSubclassOf(CBMAIndex::typeid))
		throw gcnew Exception ("Invalid base-case init");
}
#ifdef HANDLE
Cephei::QL::Indexes::CBMAIndex::CBMAIndex (QuantLib::Handle<QuantLib::BMAIndex>& childNative, Object^ owner)  : CInterestRateIndex(CBMAIndex::typeid)
{
	_phBMAIndex = &childNative;
	_ppBMAIndex = &static_cast<boost::shared_ptr<QuantLib::BMAIndex>>(childNative.currentLink());
    _ppInterestRateIndex = new boost::shared_ptr<QuantLib::InterestRateIndex> (boost::dynamic_pointer_cast<QuantLib::InterestRateIndex> (*_ppBMAIndex));
    _BMAIndexOwner = owner;
}
Cephei::QL::Indexes::CBMAIndex::CBMAIndex (QuantLib::Handle<QuantLib::BMAIndex> childNative)  : CInterestRateIndex(CBMAIndex::typeid)
{
	_phBMAIndex = &childNative;
	_ppBMAIndex = &static_cast<boost::shared_ptr<QuantLib::BMAIndex>>(childNative.currentLink());
    _ppInterestRateIndex = new boost::shared_ptr<QuantLib::InterestRateIndex> (boost::dynamic_pointer_cast<QuantLib::InterestRateIndex> (*_ppBMAIndex));
}
#endif
#ifdef STRUCT
Cephei::QL::Indexes::CBMAIndex::CBMAIndex (QuantLib::BMAIndex childNative)  : CInterestRateIndex(CBMAIndex::typeid)
{
#ifdef HANDLE
	_phBMAIndex = NULL;
#endif
	_ppBMAIndex = new boost::shared_ptr<QuantLib::BMAIndex> (new QuantLib::BMAIndex (childNative));
    _ppInterestRateIndex = new boost::shared_ptr<QuantLib::InterestRateIndex> (boost::dynamic_pointer_cast<QuantLib::InterestRateIndex> (*_ppBMAIndex));
}
#endif

Cephei::QL::Indexes::CBMAIndex::~CBMAIndex ()
{
    if (_ppBMAIndex != NULL)
    {
	    delete _ppBMAIndex;
        _ppBMAIndex = NULL;
    }
}
Cephei::QL::Indexes::CBMAIndex::!CBMAIndex ()
{
    if (_ppBMAIndex != NULL)
    {
	    delete _ppBMAIndex;
    }
}
QuantLib::BMAIndex& Cephei::QL::Indexes::CBMAIndex::GetReference ()
{
    if (_ppBMAIndex == NULL) throw gcnew NativeNullException ();
	return **_ppBMAIndex;
}
boost::shared_ptr<QuantLib::BMAIndex>& Cephei::QL::Indexes::CBMAIndex::GetShared ()
{
    if (_ppBMAIndex == NULL) throw gcnew NativeNullException ();
	return *_ppBMAIndex;
}
QuantLib::BMAIndex* Cephei::QL::Indexes::CBMAIndex::GetPointer ()
{
    if (_ppBMAIndex == NULL) throw gcnew NativeNullException ();
	return &**_ppBMAIndex;
}
#ifdef HANDLE
QuantLib::Handle<QuantLib::BMAIndex>& Cephei::QL::Indexes::CBMAIndex::GetHandle ()
{
	if (_phBMAIndex == NULL)
	{
		_phBMAIndex = new Handle<QuantLib::BMAIndex> (*_ppBMAIndex);
	}
	return *_phBMAIndex;
}
#endif
bool Cephei::QL::Indexes::CBMAIndex::HasNative () 
{
	return (_ppBMAIndex != NULL);
}

Cephei::QL::Times::ISchedule^ Cephei::QL::Indexes::CBMAIndex::FixingSchedule (DateTime start, DateTime end)
{
    try
    {
    	boost::detail::spinlock::scoped_lock lock (*_pSpinlock);
        QuantLib::Date _start = (QuantLib::Date)ValueHelper::Convert (start);
        QuantLib::Date _end = (QuantLib::Date)ValueHelper::Convert (end);
    	QuantLib::Schedule _rv = (QuantLib::Schedule)(*_ppBMAIndex)->fixingSchedule ( _start,  _end );   
        Cephei::QL::Times::CSchedule^ _nrv = gcnew Cephei::QL::Times::CSchedule (_rv);
    	return _nrv;
	}
    catch (QuantLib::Error& _error)
    {
        if (_error.what())
		    throw gcnew NativeExcpetion (gcnew System::String(_error.what()));
        else
		    throw gcnew NativeExcpetion (gcnew System::String("Unknown quantlib error"));
        
    }
	catch (std::exception& _error)
	{
        if (_error.what())
		    throw gcnew NativeExcpetion (gcnew System::String(_error.what()));
        else
		    throw gcnew NativeExcpetion (gcnew System::String("Unknown std::exception"));
	}
    finally
    {
    }
}
Boolean Cephei::QL::Indexes::CBMAIndex::IsValidFixingDate (DateTime fixingDate)
{
    try
    {
        QuantLib::Date _fixingDate = (QuantLib::Date)ValueHelper::Convert (fixingDate);
    	bool _rv = (bool)(*_ppBMAIndex)->isValidFixingDate ( _fixingDate );   
        Boolean _nrv = (Boolean)ValueHelper::Convert (_rv);
    	return _nrv;
	}
    catch (QuantLib::Error& _error)
    {
        if (_error.what())
		    throw gcnew NativeExcpetion (gcnew System::String(_error.what()));
        else
		    throw gcnew NativeExcpetion (gcnew System::String("Unknown quantlib error"));
        
    }
	catch (std::exception& _error)
	{
        if (_error.what())
		    throw gcnew NativeExcpetion (gcnew System::String(_error.what()));
        else
		    throw gcnew NativeExcpetion (gcnew System::String("Unknown std::exception"));
	}
    finally
    {
    }
}
DateTime Cephei::QL::Indexes::CBMAIndex::MaturityDate (DateTime valueDate)
{
    try
    {
        QuantLib::Date _valueDate = (QuantLib::Date)ValueHelper::Convert (valueDate);
    	QuantLib::Date _rv = (QuantLib::Date)(*_ppBMAIndex)->maturityDate ( _valueDate );   
        DateTime _nrv = (DateTime)ValueHelper::Convert (_rv);
    	return _nrv;
	}
    catch (QuantLib::Error& _error)
    {
        if (_error.what())
		    throw gcnew NativeExcpetion (gcnew System::String(_error.what()));
        else
		    throw gcnew NativeExcpetion (gcnew System::String("Unknown quantlib error"));
        
    }
	catch (std::exception& _error)
	{
        if (_error.what())
		    throw gcnew NativeExcpetion (gcnew System::String(_error.what()));
        else
		    throw gcnew NativeExcpetion (gcnew System::String("Unknown std::exception"));
	}
    finally
    {
    }
}
String^ Cephei::QL::Indexes::CBMAIndex::Name::get ()
{
    try
    {
    	std::string _rv = (std::string)(*_ppBMAIndex)->name ( );   
        String^ _nrv = (String^)ValueHelper::Convert (_rv);
    	return _nrv;
	}
    catch (QuantLib::Error& _error)
    {
        if (_error.what())
		    throw gcnew NativeExcpetion (gcnew System::String(_error.what()));
        else
		    throw gcnew NativeExcpetion (gcnew System::String("Unknown quantlib error"));
        
    }
	catch (std::exception& _error)
	{
        if (_error.what())
		    throw gcnew NativeExcpetion (gcnew System::String(_error.what()));
        else
		    throw gcnew NativeExcpetion (gcnew System::String("Unknown std::exception"));
	}
    finally
    {
    }
}
Cephei::QL::Termstructures::IYieldTermStructure^ Cephei::QL::Indexes::CBMAIndex::ForwardingTermStructure::get ()
{
    try
    {
    	Handle<QuantLib::YieldTermStructure> _rv = (Handle<QuantLib::YieldTermStructure>)(*_ppBMAIndex)->forwardingTermStructure ( );   
        Cephei::QL::Termstructures::CYieldTermStructure^ _nrv = gcnew Cephei::QL::Termstructures::CYieldTermStructure (_rv);
    	return _nrv;
	}
    catch (QuantLib::Error& _error)
    {
        if (_error.what())
		    throw gcnew NativeExcpetion (gcnew System::String(_error.what()));
        else
		    throw gcnew NativeExcpetion (gcnew System::String("Unknown quantlib error"));
        
    }
	catch (std::exception& _error)
	{
        if (_error.what())
		    throw gcnew NativeExcpetion (gcnew System::String(_error.what()));
        else
		    throw gcnew NativeExcpetion (gcnew System::String("Unknown std::exception"));
	}
    finally
    {
    }
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Factory class

Cephei::QL::Indexes::IBMAIndex^ Cephei::QL::Indexes::CBMAIndex_Factory::Create (Microsoft::FSharp::Core::FSharpOption<Cephei::QL::Termstructures::IYieldTermStructure^>^ h)
{
    return gcnew CBMAIndex ( h);
}
